<!-- *+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+ -->
<!-- File: class.ec2.php 																						-->
<!--																											-->
<!-- Adapted From: php-aws library																				-->
<!-- 			   http://code.google.com/p/php-aws/source														-->
<!--																											-->
<!-- Modified By: John Fronckowiak, IDC Consulting, Inc.														-->
<!--																											-->
<!-- Purpose: Provide an interface to the EC2 Query API															-->
<!-- *+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+ -->
<?php
  class EC2
  {
	  // class variables
      var $_key = "";								// public key
      var $_secret = "";							// private key
      var $_server = "http://ec2.amazonaws.com";	// EC2 web service URL
      var $_pathToCurl = "";						// curl path
      var $_date = null;							// request header date
      var $_error = null;							// error flag

      // initialize the EC2 object
      function EC2($key = null, $secret = null)
      {
          if ($key && $secret) {
              $this->_key = $key;
              $this->_secret = $secret;
          }
          
          // If the path to curl isn't set, try and auto-detect it
          if ($this->_pathToCurl == "") {
              $path = trim(shell_exec("which curl"), "\n ");
              if (is_executable($path))
                  $this->_pathToCurl = $path;
              else {
                  $this->_error = "Couldn't auto-detect path to curl";
                  return false;
              }
          }
          
          return true;
      }

      // retrieve the images
      function getImages($ownerId = null)
      {
		  // set the action
          $params = array("Action" => "DescribeImages");

		  // specify the ownerId parameter
          if (isset($ownerId))
              $params['Owner.1'] = $ownerId;

		  // generate the request and retrieve the xml
          $xmlstr = $this->sendRequest($params);
          $xml = new SimpleXMLElement($xmlstr);

          // parse the returned xml
          $images = array();
          foreach ($xml->imagesSet->item as $item) {
              $images[(string)$item->imageId] = array("location" => (string)$item->imageLocation, 
												      "imageId" => (string)$item->imageId, 
													   "state" => (string)$item->imageState, 
													   "owner" => (string)$item->imageOwnerId, 
													   "public" => (string)$item->isPublic);
          }

		  // return the images array
          return $images;
      }

      // register an image
      function registerImage($toRegister)
      {
          $params = array("Action" => "RegisterImage");
          $params['ImageLocation'] = $toRegister;
          $xmlstr = $this->sendRequest($params);
          $xml = new SimpleXMLElement($xmlstr);
          return $xml->imageId;
      }

      // retrieve the available images
      function getInstances()
      {
          $params = array("Action" => "DescribeInstances");
          $xmlstr = $this->sendRequest($params);
          $xml = new SimpleXMLElement($xmlstr);
          
          $instances = array();
          
          foreach ($xml->reservationSet->item as $item)
              $instances[(string)$item->instancesSet->item->instanceId] = array("instanceId" => (string)$item->instancesSet->item->instanceId, 
																			    "state" => (string)$item->instancesSet->item->instanceState->name, 
																				 "dns" => (string)$item->instancesSet->item->dnsName);
          return $instances;
      }

      // run an instance
      function runInstances($imageId, $min = 1, $max = 1, $keyName = "gsg-keypair")
      {
          $params = array("Action" => "RunInstances", "ImageId" => $imageId, "MinCount" => $min, "MaxCount" => $max, "KeyName" => $keyName);
          
          $xmlstr = $this->sendRequest($params);
          $xml = new SimpleXMLElement($xmlstr);
          
          $instances = array();
          foreach ($xml->instancesSet->item as $item)
              $instances[(string)$item->instanceId] = array("imageId" => (string)$item->imageId, 
														    "state" => (string)$item->instanceState->name, 
															"dns" => (string)$item->dnsName);
          return $instances;
      }
      
	  // get a key pair
      function getKeys()
      {
          $params = array("Action" => "DescribeKeyPairs");
          $xmlstr = $this->sendRequest($params);
          $xml = new SimpleXMLElement($xmlstr);
          
          $keys = array();
          foreach ($xml->keySet->item as $item)
              $keys[] = array("name" => (string)$item->keyName, "fingerprint" => (string)$item->keyFingerprint);
          return $keys;
      }

      // reboot the specified instance
      function rebootInstance($toReboot)
      {
          $params = array("Action" => "RebootInstances");
          $toReboot = explode(",", $toReboot);
          $i = 0;
          foreach ($toReboot as $id)
              $params['InstanceId.' . ++$i] = $id;
          $xmlstr = $this->sendRequest($params);
          $xml = new SimpleXMLElement($xmlstr);
          
          return $xml->return;
      }

      // terminate the specified instance
      function terminateInstances($toKill)
      {
          $params = array("Action" => "TerminateInstances");
          $toKill = explode(",", $toKill);
          $i = 0;
          foreach ($toKill as $id)
              $params['InstanceId.' . ++$i] = $id;
          $xmlstr = $this->sendRequest($params);
          $xml = new SimpleXMLElement($xmlstr);
          
          $instances = array();
          foreach ($xml->instancesSet->item as $item)
              $instances[(string)$item->instanceId] = array("shutdownState" => (string)$item->shutdownState, "previousState" => (string)$item->previousState);
          return $instances;
      }

      // sign and generate the EC2 request
      function sendRequest($params)
      {
          $params['AWSAccessKeyId'] = $this->_key;
          $params['SignatureVersion'] = 1;
          $params['Timestamp'] = gmdate("Y-m-d\TH:i:s\Z");
          $params['Version'] = "2006-10-01";
          uksort($params, "strnatcasecmp");
          
          $toSign = "";
          foreach ($params as $key => $val)
              $toSign .= $key . $val;
          $sha1 = $this->hasher($toSign);
          $sig = $this->base64($sha1);
          $params['Signature'] = $sig;
          
          $curl = "{$this->_pathToCurl} -s \"{$this->_server}/?";
          
          reset($params);
          foreach ($params as $key => $val)
              $curl .= "$key=" . urlencode($val) . "&";
          $curl .= '"';
          
          return `$curl`;
      }

      // create the signature
      function hasher($data)
      {
          // Algorithm adapted (stolen) from http://pear.php.net/package/Crypt_HMAC/)
          $key = $this->_secret;
          if (strlen($key) > 64)
              $key = pack("H40", sha1($key));
          if (strlen($key) < 64)
              $key = str_pad($key, 64, chr(0));
          $ipad = (substr($key, 0, 64) ^ str_repeat(chr(0x36), 64));
          $opad = (substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64));
          return sha1($opad . pack("H40", sha1($ipad . $data)));
      }

      // generate the base64 signature
      function base64($str)
      {
          $ret = "";
          for ($i = 0; $i < strlen($str); $i += 2)
              $ret .= chr(hexdec(substr($str, $i, 2)));
          return base64_encode($ret);
      }
  }
?>